#pragma once

#include <windows.h>
#include <map>

#include "collectionbox.h"
#include "imagebox.h"
#include "tabcontrol.h"
#include "window.h"

class ImageTab;
class Task;

/** 
 * \ingroup ti6
 *
 * \brief
 * The MainWindow class represents the application window and handles all
 * messages which are send to this window. The class is thus responsible
 * for most of the event handling in the application.
 * MainWindow is a singleton class. The instance contains - among others -
 * a TabControl, an ImageBox and a CollectionBox. It redirects calls for
 * the menu (load/save file, new collection, filters...) to various methods
 * in the application. MainWindow can be seen as the most important class
 * in the application.
 *
 * Copyright (c) Academie voor ICT en Media 2007 - 2008
 */
class MainWindow: public Window
{
	/*
	 Specify the MenuFunc type as a pointer to member function, which is
	 a member of MainWindow, has one parameter (type WORD) and does not
	 return a value (void).
	 */
	typedef void (MainWindow::*MenuFunc)( WORD );

public:
	/**
	 \brief
	 Deconstructor.
	 */
	~MainWindow();

	/**
	 \brief
	 Get the singleton instance of this class. If this instance does
	 not exist, it will be created. Please note that, if the instance
	 is created, it has to be initialized using create().
	 
	 \return A pointer to the singleton instance.
	 */
	static MainWindow* instance();

	/**
	 \brief
	 Initialize the instance. This will register the window class if
	 neccesary and create the window itself.
	 
	 \param hWndParent Handle to the parent window.
	 \param hInstance Instance handle.
	 \return True is returned if the window is successfully created. In
	   case of an error, false is returned.
	 */
	bool create( HWND hWndParent, HINSTANCE hInstance );

	/**
	 \brief
	 Set the visibility of the window.
	 
	 \param nCmdShow SW_SHOW to show the window, SW_HIDE to make the window
	   invisible.
	 */
	bool show( int nCmdShow );

	/**
	 \brief
	 Handle messages, specific for this window.
	 
	 \param uMsg The message id.
	 \param wParam 32 bits value, specific to the message.
	 \param lParam 32 bits value, specific to the message.
	 \return The result of the processing, which is dependent on the type of message.
	 */
	virtual LRESULT handleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam );

	/**
	 \brief
	 Get a handle to the window. Do not close this handle.

	 \return A handle to this window.
	 */
	HWND hWnd() const;

	/**
	 \brief
	 Get the instance handle. In the kernel, this is the identifier for
	 the module (in this case, the application).

	 \return The instance handle.
	 */
	HINSTANCE hInstance() const;

private:
	/**
	 \brief
	 Default constructor. Only the instance() function should create
	 an instance of MainWindow. After default construction, the instance
	 has to be initialized using create().
	 */
	MainWindow();

	/**
	 \brief
	 Set the size and position of all controls within this window. This
	 may be necessary when the size of the window is changed.
	 
	 \param *size The client size of the window. Specify NULL to use the
	   actual window size.
	 */
	void layout( SIZE *size );

	/**
	 \brief
	 Register the window class. This is a 'template' for windows which
	 is registered in the kernel. The window class for the main window
	 is registered under the name "MainWindow".

	 \param hInstance The instance handle.
	 \return If the window class is successfully registered, true is
	   returned. False is returned in case of an error.
	 */
	static bool registerWndClass( HINSTANCE hInstance );

	/**
	 \brief
	 Open an image. This will read the file and create a new tab to show the image.
	 
	 \param *fileName The file name of the image, as a wide character string. This
	   must be a valid filename for an image in BMP format.
	 \return True is returned if the image is successfully opened. In case of an
	   error, false is returned.
	 */
	bool openImage( wchar_t *fileName );

	/**
	 \brief
	 Open an image as a thumbnail. This will read the file and resize the image
	 to fit within 120 by 100 pixels.
	 
	 \param *fileName The file name of the image, as a wide character string.
	   This must be a valid filename for an image in BMP format.
	 \return A pointer to the thumbnail (as a DIB) is returned. Delete this value
	   using delete. In case of an error, NULL is returned.
	 */
	DIB* openAsThumbnail( wchar_t *fileName );
	
	/**
	 \brief
	 Open an image. This will pop up an open file dialog and call openImage()
	 when a file is selected.
	 
	 \param WORD Dummy parameter, to make this function fit the MenuFunc type.
	 */
	void openFile( WORD = 0 );

	/**
	 \brief
	 Save the file, which is open in the current tab. This function has effect
	 only when the current tab contains an image.
	 
	 \param WORD Dummy parameter, to make this function fit the MenuFunc type.
	 */
	void saveFile( WORD = 0 );

	/**
	 \brief
	 Save the image as a new file. This will pop up the save file as dialog,
	 where the user can specify a file name. This function has effect only
	 when the current tab contains an image.
	 
	 \param WORD Dummy parameter, to make this function fit the MenuFunc type.
	 */
	void saveFileAs( WORD = 0 );

	/**
	 \brief
	 Close the current tab (and file). This has effect for images and collections.
	 When there are any unsaved changes, the user will be asked whether changes
	 should be saved.
	 
	 \param WORD Dummy parameter, to make this function fit the MenuFunc type.
	 */
	void closeFile( WORD = 0 );

	/**
	 \brief
	 Close the application. The user will be asked about any unsaved changes.
	 
	 \param WORD Dummy parameter, to make this function fit the MenuFunc type.
	 */
	void exitApplication( WORD = 0 );

	/**
	 \brief
	 Create a new collection. This will open up a new tab.
	 
	 \param WORD Dummy parameter, to make this function fit the MenuFunc type.
	 */
	void newCollection( WORD = 0 );

	/**
	 \brief
	 Add an image to the collection. This function has effect only when the
	 current tab contains a collection.
	 
	 \param WORD Dummy parameter, to make this function fit the MenuFunc type.
	 */
	void addImage( WORD = 0 );

	/**
	 \brief
	 Filter out some of the images, based on criteria on the metadata of
	 the images. This function has effect only when the current tab contains
	 a collection.
	 
	 \param WORD Dummy parameter, to make this function fit the MenuFunc type.
	 */
	void search( WORD = 0 );

	/**
	 \brief
	 Export the collection to an XML file. This will pop up a save file dialog.
	 
	 \param WORD Dummy parameter, to make this function fit the MenuFunc type.
	 */
	void exportCollection( WORD = 0 );

	/**
	 \brief
	 Show a histogram of the image.
	 
	 \param WORD Dummy parameter, to make this function fit the MenuFunc type.
	 */
	void histogram( WORD = 0 );

	/**
	 \brief
	 Perform a dot operation on the current image. The exact operation which
	 should be performed is specified by id.
	 
	 \param id The operation identifier, as defined in resource.h.
	 */
	void dotOperation( WORD id );

	/**
	 \brief
	 Perform a rebuilding operation on the current image. The exact operation which
	 should be performed is specified by id.
	 
	 \param id The operation identifier, as defined in resource.h.
	 */
	void rebuildingOperation( WORD id );

	/**
	 \brief
	 Perform a sizing operation on the current image. The exact operation which
	 should be performed is specified by id.
	 
	 \param id The operation identifier, as defined in resource.h.
	 */
	void sizingOperation( WORD id );

	/**
	 \brief
	 Perform a file operation on the current image. The exact operation which
	 should be performed is specified by id.
	 
	 \param id The operation identifier, as defined in resource.h.
	 */
	void fileOperation( WORD id );

	/**
	 \brief
	 Give a notification about the completion of a task. This will show the
	 correct image in the image box. This function will delete the task.
	 
	 \param *task The task which has been completed.
	 */
	void taskCompleted( Task *task );

	/**
	 \brief
	 Give a notification about the failure of a task. This will show a message
	 box wich will notify the user. This function will delete the task.
	 
	 \param *task The task which has failed.
	 */
	void taskFailed( Task *task );

	/**
	 \brief
	 Search for the image tab which contains the specified DIB.
	 
	 \param *dib The DIB to search for.
	 \return A pointer to the image tab which contains the DIB.
	   If this tab is not found, NULL is returned.
	 */
	ImageTab* getTabForDIB( DIB *dib );

	/**
	 A window handle for the application window.
	 */
	HWND _hWnd;

	/**
	 A window handle for the status bar.
	 */
	HWND _hWndStatusBar;

	/**
	 A window handle for the metadata button.
	 */
	HWND _hWndBtnMetaData;

	/**
	 The instance handle. In the win32 kernel, this is the identifier for the
	 module (in this case the application).
	 */
	HINSTANCE _hInstance;

	/**
	 The tab control within the main window.
	 */
	TabControl *_tabCtrl;

	/**
	 The collection box within the main window. This component is made visible
	 when the active tab is a collection tab.
	 */
	CollectionBox *_collectionBox;

	/**
	 The image box within the main window. This component is made visible when
	 the active tab is an image tab.
	 */
	ImageBox *_imageBox;

	/**
	 An associative container which stores the function to call for each menu
	 identifier. The menu identifiers are defined in resource.h and passed as
	 the low order word of wParam, in a WM_COMMAND message.
	 */
	std::map<WORD,MenuFunc> _menuFunc;

	/**
	 The singleton instance of MainWindow.
	 */
	static MainWindow *_instance;

	/**
	 The window class.
	 */
	static ATOM _wndClass;

	/*
	 The main function of this application has full access to MainWindow, in
	 order to initialize this instance and to set the instance handle (_hInstance).
	 */
	friend int CALLBACK WinMain( HINSTANCE, HINSTANCE, LPSTR, int );
};
